package com.gl.order.service.impl;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.gl.order.commom.ResultBean;
import com.gl.order.commom.util.ProcessCommonUtil;
import com.gl.order.entity.TUser;
import com.gl.order.entity.vo.DbsxInfoVo;
import com.gl.order.mapper.ProcessMapper;
import com.gl.order.security.model.SecurityUser;
import com.gl.order.service.ProcessService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@Transactional
public class ProcessServiceImpl implements ProcessService {

    @Autowired
    ProcessMapper processMapper;

    @Override
    public void saveOrUpdateLc(Map<String, String> paramMap) {
        log.info("saveOrUpdateLc-------->:新增或修改流程");
        SecurityUser principal = (SecurityUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        TUser user = principal.getCurrentUserInfo();
        paramMap.put("XGR",user.getId());
        paramMap.put("XGSJ",ProcessCommonUtil.getCurrDateStr(null));
        String wid = paramMap.get("WID");
        if (StringUtils.isEmpty(wid)) {
            paramMap.put("WID",ProcessCommonUtil.uuid());
            processMapper.addLc(paramMap);
        } else {
            processMapper.updateLc(paramMap);
        }
    }

    @Override
    public void saveOrUpdateLcJd(Map<String, String> paramMap) {
        log.info("saveOrUpdateLcJd-------->:新增或修改流程节点");
        String wid = paramMap.get("WID");
        SecurityUser principal = (SecurityUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        TUser user = principal.getCurrentUserInfo();
        paramMap.put("XGR", user.getId());
        paramMap.put("XGSJ", ProcessCommonUtil.getCurrDateStr(null));
        if (StringUtils.isEmpty(wid)) {
            paramMap.put("WID", ProcessCommonUtil.uuid());
            processMapper.addLcJd(paramMap);
        } else {
            processMapper.updateLcJd(paramMap);
        }
    }

    @Override
    public ResultBean queryProcessInfo(String zbwid) {
        List<Map<String, String>> lcResult = ProcessCommonUtil.listToUpperCase(processMapper.queryShlsByZbwid(zbwid));
        Map<String,String> params = new HashMap<String,String>();
        //获取流程ID
        String lcwid = processMapper.queryLcByZbwid(zbwid);
        params.put(ProcessCommonUtil.LC_WID,lcwid);
        params.put(ProcessCommonUtil.ZBWID,zbwid);
        //处理流程数据
        List<Map<String,String>> lList = processMapper.queryLcInfoByWid(params);
        List<Map<String,Object>> result = new ArrayList<Map<String,Object>>();
        for (int i = 0, index = 0; i < lList.size(); i++) {
            Map<String, String> jdInfo = lList.get(i);
            Map<String, Object> resultMap = new HashMap<String, Object>();
            resultMap.put("JDMC", jdInfo.get("JDMC"));
            resultMap.put("CZLX", jdInfo.get("CZLX"));
            resultMap.put("JDZT", i + 1);
            result.add(resultMap);

            String CZLX = jdInfo.get("CZLX");
            if (ProcessCommonUtil.LCZT_PASS.equals(CZLX) || ProcessCommonUtil.LCZT_NOTPASS.equals(CZLX)) {
                index = 0;
                continue;
            }
            if (ProcessCommonUtil.LCZT_AUDIT.equals(CZLX)) {
                index = index + 1;
                continue;
            }
            resultMap.put("CZLX", null);
            if (index > 0 || i == 0) {
                resultMap.put("CZLX", ProcessCommonUtil.LCZT_DRAFT);
                index = 0;
            }
        }
        Map<String,Object> resultMap = new HashMap<String,Object>();
        resultMap.put("stepTitle",result);
        resultMap.put("lcData",lcResult);
        log.info("queryLcJdInfo-------->lList：" + resultMap);
        return ResultBean.success(resultMap);
    }

    @Override
    public ResultBean auditProcess(Map<String, Object> param) throws Throwable {
        log.info("auditProcess-------->param：" + param);
        String zbwid = ProcessCommonUtil.toString(param.get(ProcessCommonUtil.ZBWID));
        String lcWid = ProcessCommonUtil.toString(param.get(ProcessCommonUtil.LC_WID));
        String jdWid = ProcessCommonUtil.toString(param.get(ProcessCommonUtil.JD_WID));
        String czlx = ProcessCommonUtil.toString(param.get(ProcessCommonUtil.CZLX));
        String shyj = ProcessCommonUtil.toString(param.get(ProcessCommonUtil.SHYJ));

        //流程状态 默认审核中
        String lczt = "100";
        if (!ProcessCommonUtil.START_PROCESS.equals(jdWid)) {
            lczt = ProcessCommonUtil.toInt(jdWid) + "";
        }

        if (!ProcessCommonUtil.CZLX_LIST.contains(czlx)) {
            throw new Throwable("操作类型不对,请确认.");
        }
        if (StringUtils.isEmpty(jdWid)) {
            throw new Throwable("未指定节点，请检查.");
        }
        if (StringUtils.isEmpty(zbwid)) {
            throw new Throwable("审核流程失败，缺少ZBWID.");
        }
        if (StringUtils.isEmpty(lcWid)) {
            throw new Throwable("审核流程失败，LC_WID.");
        }
        Map<String,String> params = new HashMap<String,String>();
        params.put(ProcessCommonUtil.LC_WID,lcWid);
        List<Map<String, String>> list = processMapper.queryLcInfoByWid(params);
        if (list == null || list.size() == 0) {
            throw new Throwable("审核流程失败，找不到对应流程.");
        }
        SecurityUser principal = (SecurityUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        TUser user = principal.getCurrentUserInfo();
        Map<String, String> saveShls = new HashMap<String, String>();
        saveShls.put(ProcessCommonUtil.WID, ProcessCommonUtil.uuid());
        saveShls.put(ProcessCommonUtil.JD_WID, jdWid);
        saveShls.put(ProcessCommonUtil.LC_WID, lcWid);
        saveShls.put(ProcessCommonUtil.JSSJ, ProcessCommonUtil.getCurrDateStr(null));
        saveShls.put(ProcessCommonUtil.SHYJ, shyj);
        saveShls.put(ProcessCommonUtil.ZBWID, zbwid);
        saveShls.put(ProcessCommonUtil.CZLX, czlx);
        //开启流程
        if (ProcessCommonUtil.START_PROCESS.equals(jdWid)) {
            param.put("DQZT", "1");
            int count = processMapper.queryDbJdIsEnd(param);
            if(count > 0) {
                throw new Throwable("该对象已开启流程,无需再次开启.");
            }
            log.info("auditProcess-------->首次开启流程");
            param.put("JDZT", "1");
            List<Map<String, String>> processList = processMapper.queryNextJd(param);
            if (processList == null || processList.size() == 0) {
                throw new Throwable("流程有问题，请检查.");
            }
            saveShls.put(ProcessCommonUtil.JDZT, "0");
            saveShls.put(ProcessCommonUtil.SH_ROLE, "");
            saveShls.put(ProcessCommonUtil.SHR, user.getId());
            saveShls.put(ProcessCommonUtil.KSSJ, ProcessCommonUtil.getCurrDateStr(null));
            processMapper.saveShls(saveShls);
            //保存下一节点代办
            saveDbsx(processList, lcWid, zbwid);
        } else {
            param.put("USER_ID", user.getId());
            Map<String, String> dbInfo = processMapper.queryGrDbData(param);
            if (dbInfo == null || dbInfo.keySet().size() == 0) {
                throw new Throwable("该用户无权限审核，请检查.");
            }
            String dqzt = dbInfo.get("DQZT");
            String curRole = dbInfo.get("SH_ROLE");
            String ddsj = dbInfo.get("DDSJ");
            saveShls.put(ProcessCommonUtil.JDZT, dqzt);
            saveShls.put(ProcessCommonUtil.SHR, user.getId());
            saveShls.put(ProcessCommonUtil.SH_ROLE, curRole);
            saveShls.put(ProcessCommonUtil.KSSJ, ddsj);
            //操作类型不通过
            if (czlx.equals(ProcessCommonUtil.CZLX_NOTPASS)) {
                processMapper.saveShls(saveShls);
                processMapper.deleteDbsx(param);
                lczt = ProcessCommonUtil.CZLX_NOTPASS;
                log.info("auditProcess-------->审核不通过");
            } else if (czlx.equals(ProcessCommonUtil.CZLX_AUDIT)) {//审核
                processMapper.deleteDbsx(param);
                param.put("DQZT", dqzt);
                int count = processMapper.queryDbJdIsEnd(param);
                //判断当前待办节点是否结束
                param.put("JDZT", ProcessCommonUtil.toInt(dqzt) + 1 + "");
                List<Map<String, String>> processList = processMapper.queryNextJd(param);
                boolean flag = processList == null || processList.size() == 0;
                if (count == 0 && flag) {
                    log.info("auditProcess-------->没有下个节点,流程结束");
                    lczt = ProcessCommonUtil.LCZT_PASS;
                    saveShls.put(ProcessCommonUtil.CZLX, ProcessCommonUtil.LCZT_PASS);
                }
                if (count == 0 && !flag) {
                    log.info("auditProcess-------->开启下个节点审核");
                    saveDbsx(processList, lcWid, zbwid);
                }
                processMapper.saveShls(saveShls);
            } else if (czlx.equals(ProcessCommonUtil.CZLX_BACK)) {//回退
                Map<String, String> jdInfo = processMapper.queryJdInfoByJdWid(jdWid);
                String jdlx = jdInfo.get("JDLX");
                //节点类型为2则为办理
                if (ProcessCommonUtil.CZLX_ACROSS_AUDIT.equals(jdlx)) {
                    throw new Throwable("办理节点，无法回退.");
                }
                int lastJd = ProcessCommonUtil.toInt(dqzt) - 1;
                processMapper.deleteDbsx(param);
                processMapper.saveShls(saveShls);
                if (lastJd > 0) {
                    param.put("JDZT", lastJd + "");
                    List<Map<String, String>> processList = processMapper.queryNextJd(param);
                    log.info("auditProcess-------->开启上个个节点待办");
                    saveDbsx(processList, lcWid, zbwid);
                }
                lczt = lastJd + "";
            } else if (czlx.equals(ProcessCommonUtil.CZLX_ACROSS_BACK)) {//跨节点回退

            } else if (czlx.equals(ProcessCommonUtil.CZLX_ACROSS_AUDIT)) {//跨节点审核

            }
        }

        String tableName = processMapper.queryLcTable(lcWid);
        if(StringUtils.isEmpty(tableName)){
            log.info("auditProcess-------->没有指定表名,不进行会写");
            return ResultBean.success();
        }
        List<Map<String,String>> columns = processMapper.queryTableInfo(tableName);
        if(columns == null || columns.size()==0){
            log.info("auditProcess-------->表不存在,不进行回写");
            return ResultBean.success();
        }
        Map<String,Object> writeData = new HashMap<String,Object>();
        StringBuilder builder = new StringBuilder();
        if(param.get("writeData") instanceof  Map) {
            writeData = (Map<String, Object>) param.get("writeData");
        }
        if(writeData == null || writeData.keySet().size() == 0) {
            log.info("auditProcess-------->没有需要回写的数据");
        }else {
            for (Map<String,String> columnInfo : columns) {
                String dataType = columnInfo.get("DATA_TYPE");
                String columnName = columnInfo.get("COLUMN_NAME");
                if(null == writeData.get(columnName)) {
                    log.info("auditProcess-------->返回数据没有该字段:" + columnName);
                    continue;
                }
                builder.append(" , ");
                builder.append(columnName);
                builder.append(" = ");
                builder.append(toValue(writeData.get(columnName), dataType));
            }
        }
        if(builder.toString().length()>0){
            writeData.put("sql",builder.toString());
        }
        writeData.put(ProcessCommonUtil.TABLE_NAME,tableName);
        writeData.put(ProcessCommonUtil.ZBWID,"'"+zbwid+"'");
        writeData.put("state",lczt);
        processMapper.updateZbData(writeData);
        return ResultBean.success();
    }

    private String toValue(Object obj, String dataType) {
        return "'" + ProcessCommonUtil.toString(obj) + "'";
    }


    /**
     * 保存审核历史
     * @param param
     */
    private void saveShls(Map<String,String> param) {
        param.put(ProcessCommonUtil.WID, ProcessCommonUtil.uuid());
    }

    /**
     * 保存代办事项
     * @param processList
     * @param lcWid
     * @param zbwid
     */
    private void saveDbsx(List<Map<String, String>> processList,String lcWid,String zbwid) {
        final String currDate = ProcessCommonUtil.getCurrDateStr(null);
        for (Map<String, String> lcMap : processList) {
            Map<String, String> param = new HashMap<String, String>();
            param.put(ProcessCommonUtil.WID, ProcessCommonUtil.uuid());
            param.put(ProcessCommonUtil.DQZT, lcMap.get(ProcessCommonUtil.JDZT));
            param.put(ProcessCommonUtil.LC_WID, lcWid);
            param.put(ProcessCommonUtil.ZBWID, zbwid);
            param.put(ProcessCommonUtil.DDSJ, currDate);
            param.put(ProcessCommonUtil.JD_WID, lcMap.get(ProcessCommonUtil.WID));
            param.put(ProcessCommonUtil.SH_ROLE, lcMap.get(ProcessCommonUtil.SH_ROLE));
            processMapper.saveDbsx(param);
        }
    }

    @Override
    public ResultBean queryDbsxData(Map<String, Object> param) {
        SecurityUser principal = (SecurityUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        TUser user = principal.getCurrentUserInfo();
        param.put("userid",user.getId());
        log.info("queryDbsxData-------->userId：" + user.getId());
        int count = processMapper.queryDbsxCount(param);
        Map<String, Object> resultMap = new HashMap<String, Object>();
        if (count == 0) {
            resultMap.put("count", 0);
            resultMap.put("curPage", 1);
            resultMap.put("data", new ArrayList());
            return ResultBean.success(resultMap);
        }
        int pageSize = ProcessCommonUtil.toInt(param.get("pageSize"));
        int curPage = ProcessCommonUtil.toInt(param.get("curPage"));
        if (pageSize == 0 || pageSize < 0) {
            pageSize = 10;
        }
        if (curPage == 0 || curPage < 0) {
            curPage = 1;
        }
        int page = (count % pageSize > 0) ? (count / pageSize + 1) : (count / pageSize);
        curPage = (curPage > page) ? 1 : curPage;
        int startNum = (curPage - 1) * pageSize;
        int endNum = startNum + pageSize;
        param.put("startNum", startNum);
        param.put("endNum", endNum);
        List<Map<String, String>> result = ProcessCommonUtil.listToUpperCase(processMapper.queryDbsxInfo(param));
        resultMap.put("data", result);
        resultMap.put("page", page);
        resultMap.put("count", count);
        resultMap.put("curPage",curPage);
        return ResultBean.success(resultMap);
    }

    @Override
    public ResultBean queryConfigColumns(String jdwid) {
        return ResultBean.success(processMapper.queryConfigColumns(jdwid));
    }

    @Override
    public void excelExport(HttpServletResponse response, Map<String, Object> paramMap) throws IOException {
        SecurityUser principal = (SecurityUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        TUser user = principal.getCurrentUserInfo();
        paramMap.put("userid",user.getId());
        List<DbsxInfoVo> list = processMapper.queryAllDbsxInfo(paramMap);
        ExcelWriter writer = ExcelUtil.getWriter(true);
        //自定义标题别名
        writer.addHeaderAlias("orderNo", "订单号");
        writer.addHeaderAlias("name", "订单名称");
        writer.addHeaderAlias("patternprocess", "印花工艺");
        writer.addHeaderAlias("jdmc", "审核节点");
        writer.addHeaderAlias("productRemark", "备注");
        writer.addHeaderAlias("shipmentTime", "出货时间");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        String name = "订单流程-" + System.currentTimeMillis();
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name + ".xlsx", "UTF-8") + "");
        OutputStream os = response.getOutputStream();
        writer.write(list, true);
//        SXSSFSheet sheet = (SXSSFSheet) writer.getSheet();
//        sheet.trackAllColumnsForAutoSizing();
        writer.autoSizeColumnAll();
        writer.flush(os);
        writer.close();
    }

}
